<template>
  <div class="hy-swiper">
    <div class="swiper">
        <div v-for="banner in list" :key="typeof banner == 'object' ? banner[linkKey] : banner" class="slide"
            @touchstart="touchStart" @touchmove="touchMove" @touchend="touchEnd">
            <a :href="typeof banner == 'object' ? banner[linkKey] : banner">
              <img :src="typeof banner == 'object' ? banner[bgKey] : banner" @load="imageLoad" />
            </a>
        </div>
    </div>
    <div class="indicator" v-if="slideCount > 1">
      <div v-for="(item, index) in slideCount" :key="index" class="indi-item"
          :class="{active: index == currentIndex}" @click="setIndex(index)"></div>
    </div>
  </div>
</template>
<script>
import {sleep, debounce} from 'common/utils'

const emit = debounce(vue => {
  vue.$bus.$emit('swiper-image-load');
}, 1000);

export default {
  name: "Swiper",
  data: () => ({
    currentIndex: 0, // 当前的index
    scrolling: false, // 是否正在滚动
    slideCount: 0, // 元素个数
    totalWidth: 0, // swiper 的宽度
    swiperStyle: {}, // swiper 样式
    positions: [],
    get currentPosition() {
      return this.positions[this.currentIndex];
    }
  }),
  props: {
    list: Array,
    linkKey: {
      type: String,
      default: "link"
    }, // image 的属性key
    bgKey: {
      type: String,
      default: "background"
    },
    widthKey: {
      type: String,
      default: "width"
    },
    heightKey: {
      type: String,
      default: "height"
    },
    interval: {
      type: Number,
      default: 3000
    },
    animDuration: {
      type: Number,
      default: 300
    },
    moveRatio: {
      type: Number,
      default: 0.25
    },
    emitLoad: {
      type: Boolean,
      default: false
    }
  },
  methods: {
    /**
     * 操作 DOM, 在 DOM前后添加Slide
     **/
    handleDom() {
      let swiper = document.querySelector('.swiper');
      let slides = swiper.getElementsByClassName('slide');

      this.slideCount = slides.length;

      if (this.slideCount > 1) { // 如果大于 1 个, 那么在前后分别添加一个 slide

        let cloneFirst = slides[0].cloneNode(true);
        let cloneLast = slides[this.slideCount - 1].cloneNode(true);

        swiper.insertBefore(cloneLast, slides[0]);
        swiper.appendChild(cloneFirst);

        this.totalWidth = swiper.offsetWidth;
        this.swiperStyle = swiper.style;

        for (let i in this.list) {
          this.positions.push(- (parseInt(i) + 1) * this.totalWidth);
        }
      }

      // 让swiper元素,显示第一个
      this.setTransform(-this.totalWidth);
    },
    increIndex() {
      this.setIndex((this.currentIndex + 1) % this.slideCount);
    },
    decrIndex() {
      this.setIndex((this.currentIndex - 1 + this.slideCount) % this.slideCount);
    },
    setIndex(index) {
      this.currentIndex = index;
    },

    /**
     * 启动定时器
     **/
    startTimer() {
      this.timer = setInterval(function (swiper) {
        swiper.increIndex();
      }, this.interval, this);
    },
    stopTimer() {
      clearInterval(this.timer);
    },


    /**
     * 拖动事件处理
     **/
    touchStart(e) {
      // 如果正在滚动, 取消拖动
      if (this.scrolling) return;

      // 停止定时器
      this.stopTimer();

      // 保存开始滚动的位置
      this.startX = e.touches[0].pageX;
    },
    touchMove(e) {
      // 计算出用户拖动的距离
      let currentX = e.touches[0].pageX;
      this.distance = currentX - this.startX;
      let moveDistance = this.distance + this.currentPosition;

      // 设置当前的位置
      this.setTransform(moveDistance);
    },
    touchEnd(e) {
      // 获取移动距离
      let distan = Math.abs(this.distance);

      if (distan > this.totalWidth * this.moveRatio) {
        this.distance > 0 ? this.decrIndex() : this.increIndex();
      } else {
        return;
      }
      this.scrollContent(this.currentPosition); // 移动到计算后位置

      this.startTimer(); // 启动定时器
    },


    /**
     * 滚动到正确的位置
     **/
    scrollContent(currentPosition) {
      // while (this.scrolling) sleep(10);

      this.scrolling = true; // 设置正在滚动

      // 开始滚动动画
      this.swiperStyle.transition = 'transform ' + this.animDuration + 'ms';
      this.setTransform(currentPosition);

      // 判断滚动到的位置
      this.checkPosition();

      // 滚动完成
      this.scrolling = false;
    },
    checkPosition() {
      setTimeout(() => {
        // 校验正确的位置
        this.swiperStyle.transition = '0ms';
        this.setTransform(this.currentPosition);

        // 结束移动后的回调
        // this.$emit('transitionEnd', this.currentIndex);
      }, this.animDuration);
    },

    /**
     * 设置滚动的位置
     **/
    setTransform(position) {
      this.swiperStyle.transform = `translate3d(${position}px, 0, 0)`;
      this.swiperStyle['-webkit-transform'] = this.swiperStyle.transform;
      this.swiperStyle['-ms-transform'] = this.swiperStyle.transform;
    },
    imageLoad() {
      if (this.emitLoad) {
        emit(this);
      }
    }
  },

  mounted() {
    setTimeout(function (swiper) {
      swiper.handleDom();

      swiper.startTimer();
    }, 100, this);
  },
  watch: {
    currentPosition: {
      handler(newPosition) {
        this.scrollContent(newPosition);
      }
    }
  }
}
</script>
<style scoped>
  /* @import "~assets/css/base.css"; */

  .hy-swiper {
    overflow: hidden;
    position: relative;
  }

  .swiper {
    display: flex;
  }

  .slide {
    width: 100%;
    flex-shrink: 0;
  }

  .slide img {
    width: 100%;
  }

  .indicator {
    display: flex;
    justify-content: center;
    position: absolute;
    width: 100%;
    bottom: 0px;
  }

  .indi-item {
    box-sizing: border-box;
    width: 8px;
    height: 8px;
    border-radius: 4px;
    background-color: #fff;
    line-height: 8px;
    text-align: center;
    font-size: 12px;
    margin: 0 5px;
  }

  .indi-item.active {
    background-color: rgba(212, 62, 46, 1.0);
  }
</style>
